Skip to content

feat: 新增 /upload_flash_transfer 文件闪传上传#113

Open
kengwang wants to merge 1 commit into
LagrangeDev:mainfrom
kengwang:feat/upload-flash-transfer
Open

feat: 新增 /upload_flash_transfer 文件闪传上传#113
kengwang wants to merge 1 commit into
LagrangeDev:mainfrom
kengwang:feat/upload-flash-transfer

Conversation

@kengwang
Copy link
Copy Markdown
Contributor

@kengwang kengwang commented Jun 5, 2026

新增文件闪传上传

Copilot AI review requested due to automatic review settings June 5, 2026 14:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds end-to-end support for “flash transfer” uploads, including a new Milky API endpoint and the corresponding Core protocol/services and upload context changes.

Changes:

  • Introduces upload_flash_transfer API handler + JSON source-gen registration.
  • Adds Core flash transfer events, protobuf packet models, and OIDB services to create/register/upload/complete file sets.
  • Extends FlashTransferContext and OperationLogic to perform chunked uploads with file binding metadata.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
Lagrange.Milky/Utility/JsonUtility.cs Registers flash transfer DTOs for System.Text.Json source generation.
Lagrange.Milky/Api/Handler/File/UploadFlashTransferHandler.cs Adds the upload_flash_transfer API handler and request/response DTOs.
Lagrange.Core/Internal/Services/System/FlashTransferService.cs Implements OIDB services for flash transfer file set lifecycle and upload steps.
Lagrange.Core/Internal/Services/System/FetchGroupMembersService.cs Updates the OIDB service route string for fetching group members.
Lagrange.Core/Internal/Packets/Service/FlashTransferUploadReq.cs Renames/provides additional upload request fields (e.g., binding) for chunk uploads.
Lagrange.Core/Internal/Packets/Service/FlashTransfer.cs Adds protobuf models for flash transfer requests/responses.
Lagrange.Core/Internal/Logic/OperationLogic.cs Adds UploadFlashTransfer workflow orchestration in core logic.
Lagrange.Core/Internal/Events/System/FlashTransferEvent.cs Introduces internal events and file metadata helpers for flash transfer.
Lagrange.Core/Internal/Context/FlashTransferContext.cs Extends chunk upload to support upload index, binding, and configurable upload URL.
Lagrange.Core/Common/Response/BotFlashTransferUpload.cs Adds a Core response model for flash transfer upload results.
Lagrange.Core/Common/Interface/MessageExt.cs Exposes UploadFlashTransfer as a BotContext extension method.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +36 to +54
public class UploadFlashTransferParameter(List<UploadFlashTransferFileParameter> files, string? title = null)
{
[JsonRequired]
[JsonPropertyName("files")]
public List<UploadFlashTransferFileParameter> Files { get; init; } = files;

[JsonPropertyName("fileset_name")]
public string? Title { get; init; } = title;
}

public class UploadFlashTransferFileParameter(string fileUri, string? fileName = null)
{
[JsonRequired]
[JsonPropertyName("file_uri")]
public string FileUri { get; init; } = fileUri;

[JsonPropertyName("file_name")]
public string? FileName { get; init; } = fileName;
}
Comment on lines +314 to +324
internal static string ResolveAsciiTitle(string title)
{
Span<char> chars = stackalloc char[title.Length];
int length = 0;
foreach (char c in title)
{
chars[length++] = c < 128 && !char.IsWhiteSpace(c) ? c : '_';
}

return new string(chars[..length]);
}
Comment on lines +268 to +300
uint uploadScene = 3;
foreach (var file in flashTransferFiles)
{
var authorize = await context.EventContext.SendEvent<FlashTransferUploadAuthorizeEventResp>(new FlashTransferUploadAuthorizeEventReq(createResp.FileSetId, file, uploadScene++));

if (string.IsNullOrEmpty(authorize.UploadToken) && string.IsNullOrEmpty(authorize.ResourceKey))
{
context.LogWarning(Tag,
"FlashTransfer authorize returned neither upload token nor resource key: fileName={0}, fileId={1}, index={2}, size={3}, host={4}, appId={5}, bindingStage={6}, bindingField5={7}, bindingField6={8}",
null,
file.FileName,
file.FileId,
file.Index,
file.Stream.Length,
authorize.UploadHost,
authorize.AppId,
authorize.BindingStage,
authorize.BindingField5,
authorize.BindingField6);
throw new OperationException(-1, $"FlashTransfer upload authorization did not return an upload token or resource key for file {file.FileName}");
}

uint bindingStage = authorize.BindingStage == 0 ? file.Index : authorize.BindingStage;
if (!string.IsNullOrEmpty(authorize.UploadToken))
{
bool success = await context.FlashTransferContext.UploadFile(authorize.UploadToken, authorize.UploadHost, authorize.AppId, file.Index, createResp.FileSetId, file.FileId, bindingStage, file.FileType, authorize.BindingField5, authorize.BindingField6, file.Stream);
if (!success) throw new OperationException(-1, "FlashTransfer file upload failed");
}

await context.EventContext.SendEvent<FlashTransferUploadCompleteEventResp>(new FlashTransferUploadCompleteEventReq(createResp.FileSetId, file, authorize.ResourceKey, uploadScene++, bindingStage, authorize.BindingField5, authorize.BindingField6));
}

await context.EventContext.SendEvent<FlashTransferUpdateFileSetStatusEventResp>(new FlashTransferUpdateFileSetStatusEventReq(createResp.FileSetId, 6));
return await UploadFile(uploadToken, appId, uploadIndex, bodyStream, binding, $"https://{uploadHost}/sliceupload");
}

private async Task<bool> UploadFile(string uKey, uint appId, uint uploadIndex, Stream bodyStream, FlashTransferUploadFileBinding? binding, string? url)
}

private async Task<bool> UploadChunk(string uKey, uint appId, uint start, FlashTransferSha1StateV chunkSha1S, byte[] body)
private async Task<bool> UploadChunk(string uKey, uint appId, uint uploadIndex, uint start, FlashTransferSha1StateV chunkSha1S, byte[] body, FlashTransferUploadFileBinding? binding, string? url)
};
var payload = ProtoHelper.Serialize(req).ToArray();
var request = new HttpRequestMessage(HttpMethod.Post, _url)
var request = new HttpRequestMessage(HttpMethod.Post, url)
KusaGumina
KusaGumina previously approved these changes Jun 5, 2026
`/upload_flash_transfer`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants